CloudFormation Challenge
Overview
I was tasked with creating a CloudFormation template that would deploy:
- An Amazon Virtual Private Cloud (VPC)
- An internet gateway attached to the VPC
- Security groups for the VPC configured to allow SSH from anywhere
- A private subnet within the VPC
- An Amazon EC2 instance (T3.micro) within the private subnet
The goal was to build and test the solution until all components deployed successfully.
My Step-by-Step Approach
Step 1: Understanding the Requirements
First, I thoroughly reviewed the requirements to ensure I understood each component needed in the CloudFormation template. I noted that I didn't need to actually access the EC2 instance via SSH, just set up the infrastructure correctly.
Step 2: Creating the CloudFormation Template
I began by creating a YAML file for my CloudFormation template. Using the terminal provided in the environment, I ran:
nano vpc-ec2-template.yaml
Then I wrote the following CloudFormation template:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Template for creating a VPC, Internet Gateway, Security Group, Private Subnet, and EC2 instance'
Resources:
# Create a VPC
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: MyLabVPC
# Create an Internet Gateway
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: MyLabInternetGateway
# Attach the Internet Gateway to the VPC
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref MyVPC
InternetGatewayId: !Ref MyInternetGateway
# Create a Private Subnet
MyPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref MyVPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: MyLabPrivateSubnet
# Create a Route Table
MyRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: MyLabRouteTable
# Create a Route to the Internet Gateway
MyRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref MyRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
# Associate the Route Table with the Subnet
MySubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref MyPrivateSubnet
RouteTableId: !Ref MyRouteTable
# Create a Security Group for SSH
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH from anywhere
VpcId: !Ref MyVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: MyLabSecurityGroup
# Create an EC2 Instance
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t3.micro
SecurityGroupIds:
- !Ref MySecurityGroup
SubnetId: !Ref MyPrivateSubnet
ImageId: ami-0df435f331839b2d6 # Amazon Linux 2 AMI in us-west-2
Tags:
- Key: Name
Value: MyLabEC2Instance
Outputs:
VpcId:
Description: The ID of the VPC
Value: !Ref MyVPC
PrivateSubnetId:
Description: The ID of the private subnet
Value: !Ref MyPrivateSubnet
InstanceId:
Description: The ID of the EC2 instance
Value: !Ref MyEC2Instance
I saved the file using CTRL+O followed by Enter, then exited the editor with CTRL+X.
Step 3: Validating My Template
Before deploying, I validated my template to catch any syntax errors:
aws cloudformation validate-template --template-body file://vpc-ec2-template.yaml
The validation was successful, showing no errors in my template structure.
Step 4: Deploying the CloudFormation Stack
I then deployed my template using the AWS CLI:
aws cloudformation create-stack \
--stack-name ReStartChallengeLabStack \
--template-body file://vpc-ec2-template.yaml \
--capabilities CAPABILITY_IAM
I included the CAPABILITY_IAM flag as a best practice, even though my template didn't include IAM resources.
Step 5: Monitoring the Stack Creation
To track the progress of my stack creation, I ran:
aws cloudformation describe-stacks --stack-name ReStartChallengeLabStack
Initially, the stack status showed CREATE_IN_PROGRESS. I periodically checked the status until it changed to CREATE_COMPLETE.
For more detailed information about the creation events, I used:
aws cloudformation describe-stack-events --stack-name ReStartChallengeLabStack
This helped me see each resource being created in sequence and ensure everything was proceeding correctly.
Step 6: Verifying the Created Resources
Once the stack completed successfully, I verified each resource was created properly:
Checking the VPC:
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=MyLabVPC"
Output confirmed my VPC was created with CIDR block 10.0.0.0/16.
Checking the EC2 instance:
aws ec2 describe-instances --filters "Name=tag:Name,Values=MyLabEC2Instance"
Confirmed my t3.micro instance was running in the correct subnet.
Checking the subnet:
aws ec2 describe-subnets --filters "Name=tag:Name,Values=MyLabPrivateSubnet"
Confirmed the subnet was created with CIDR block 10.0.1.0/24.
Checking the security group:
aws ec2 describe-security-groups --filters "Name=tag:Name,Values=MyLabSecurityGroup"
Verified that the security group had the correct ingress rule allowing SSH from anywhere (port 22).
Step 7: Understanding Key Components in My Template
During this process, I made sure I understood the purpose of each resource in my template:
- VPC (MyVPC): The foundation network container with CIDR block 10.0.0.0/16
- Internet Gateway (MyInternetGateway): Allows communication between my VPC and the internet
- VPC Gateway Attachment (AttachGateway): Links the Internet Gateway to my VPC
- Subnet (MyPrivateSubnet): A network segment within my VPC using CIDR block 10.0.1.0/24
- Route Table (MyRouteTable): Contains rules to determine where network traffic is directed
- Route (MyRoute): A rule sending all outbound traffic (0.0.0.0/0) to the Internet Gateway
- Subnet Route Table Association (MySubnetRouteTableAssociation): Links my route table to my subnet
- Security Group (MySecurityGroup): Acts as a virtual firewall, allowing SSH inbound access
- EC2 Instance (MyEC2Instance): My t3.micro EC2 instance running in the private subnet
Step 8: Important Observations
I noted several important aspects of my implementation:
- AMI Selection: I used ami-0df435f331839b2d6, which is an Amazon Linux 2 AMI in the us-west-2 region. If I were to deploy in a different region, I would need to update this ID accordingly.
- Subnet Configuration: Although the lab called for a "private subnet," I connected it to an Internet Gateway via a route table to allow SSH access. In a production environment, a truly private subnet would not have a direct route to the internet.
- Security Group Settings: I configured the security group to allow SSH access from anywhere (0.0.0.0/0). In a production environment, I would restrict this to specific IP ranges for better security.
- Template Structure: I organized my template with clear comments and logical grouping of resources to make it easy to understand and maintain.
- Outputs Section: I included an Outputs section to easily retrieve the IDs of key resources after creation.
Final Step: Demonstrating
While verifying all components were successfully created I made sure:
- The CloudFormation template I created
- The CloudFormation stack in CREATE_COMPLETE status
- The resources that were created (VPC, subnet, internet gateway, route table, security group, and EC2 instance)
It was confirmed that my solution met all the requirements
Conclusion
This process gave me hands-on experience with Infrastructure as Code using AWS CloudFormation. I successfully created a template that deployed a VPC with all the required components including an EC2 instance. The approach of using CloudFormation instead of manually creating resources demonstrated the power of automation in cloud infrastructure deployment.
Through this process, I gained valuable experience with:
- Writing CloudFormation templates in YAML
- Using the AWS CLI to validate and deploy templates
- Configuring networking components like VPCs, subnets, and route tables
- Setting up security groups for access control
- Monitoring and verifying resource creation
This knowledge will be useful for future AWS infrastructure deployments where automation and repeatability are important.